import Queue, threading, sys
from threading import Thread
import time

threadpool = None

class WorkThread(Thread):
    def __init__(self, manager):
        Thread.__init__(self)
        self._manager = manager
    
    def run(self):
        while True:
            task = self._manager.GetTask()
            if task:
                try:
                    callable, args, kwds = task
                    callable(*args, **kwds)
                except Exception,msg:
                    pass
                finally:
                    self._manager.TaskDone()
            else:
                self._manager.WorkerKilled(self)
                break

class ThreadPool:
    def __init__(self, threadcount = 20, timeout = None):
        self._taskqueue = []
        self._threads = []
        self._timeout = timeout
        self.maxthreadcount = threadcount
        self._mutex = threading.Lock()
        self._notEmpty = threading.Condition(self._mutex)
        self._allTaskDone = threading.Condition(self._mutex)
        self._workerMutex = threading.Lock()
        self._workerKill = threading.Condition(self._workerMutex)
        self._workerKilling = False
        self._valid = True
        
        self._createThreads(5)
        
    def _createThreads(self, threadcount):
        with self._workerMutex:
            for i in range(threadcount):
                self._threads.append(WorkThread(self))
                print "thread count: %d" % len(self._threads)
            
    def Start(self):
        for t in self._threads:
            t.start()
            
    def Stop(self):
        self.WaitAllComplete()
        self.KillAllWorker()
    
    def WaitAllComplete(self):
        with self._mutex:
            while len(self._taskqueue) > 0:
                self._allTaskDone.wait()
                
    def KillAllWorker(self):
        with self._workerMutex:
            self._valid = False
            while len(self._threads) > 0:
                self._workerKilling = True
                with self._mutex:
                    self._notEmpty.notify()
                self._workerKill.wait()
                self._workerKilling = False
                print "thread count: %d" % len(self._threads) 
                
    def _IncThread(self):
        with self._workerMutex:
            for i in range(5):
                if len(self._threads) >= self.maxthreadcount:
                    return
                t = WorkThread(self)
                self._threads.append(t)
                t.start()
            print "thread count: %d" % len(self._threads)
                
    def AddTask(self, callobj, *args, **kwargs):
        with self._mutex:
            if callable(callobj):
                self._taskqueue.append((callobj, args, kwargs))
                self._notEmpty.notify()
            else:
                return
                
            if len(self._taskqueue) > 5:
                self._IncThread()
                
    def GetTask(self):
        with self._mutex:
            while len(self._taskqueue) == 0 and self._valid:
                self._notEmpty.wait(self._timeout)
                
            if len(self._taskqueue) > 0:
                return self._taskqueue.pop(0)
            else:
                return None
            
    def GetTaskCount(self):
        with self._mutex:
            return len(self._taskqueue)
        
    def TaskDone(self):
        with self._mutex:
            if len(self._taskqueue) == 0:
                self._allTaskDone.notify_all()
                
    def WorkerKilled(self, worker):
        with self._workerMutex:
            self._threads.remove(worker)
            if self._workerKilling:
                self._workerKill.notify()
                
    def GetWorkerCount(self):
        with self._workerMutex:
            return len(self._threads)